/***************************************************************************
 *   Copyright (C) 2007 by Leonid Krashenko   *
 *   Leonid.Krashenko@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "nsNodes.h"
#include "NScriptTraverser.h"
#include "iSymtable.h"
#include "neiderra/core/iException.h"

#include <algorithm>

using namespace neiderra::utils;
using namespace neiderra::utils::script;
using namespace neiderra::core;

//
// nsNode implementation
//

nsNode::nsNode()
{
	_size = 0;
	type = 0;
	parent = 0;
}

void nsNode::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

void nsNode::setParent(nsNode* parent)
{
	this->parent = parent;
}

nsNode* nsNode::getParent()
{
	return parent;
}

void nsNode::setType(nsClass* type)
{
	this->type = type;
}

nsClass* nsNode::getType()
{
	return type;
}

void nsNode::setName(const string& name)
{
	this->name = name;
}

string nsNode::getName()
{
	return name;
}

void nsNode::setShortName(const string& name)
{
	_shortName = name;
}

string nsNode::getShortName()
{
	return _shortName;
}

//
// nsFunction 
//

nsFunc::nsFunc()
{
	_isMethod = false;
}

void nsFunc::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
//	params->traverse(tr);
//	body->traverse(tr);
}

nsNodes* nsFunc::collect_decs()
{
	nsNodes* collected = new nsNodes;
	int i = body->stmts->count();
	for(int j=0; j<=i; j++)
	{
		nsNode* n = body->getStmtList()->getByNum(j);
		if(n) {
			// if 'n' is declaration
			if(dynamic_cast<nsVar*>(n) || 
						dynamic_cast<nsFunc*>(n) 
//				dynamic_cast<nsClass*>(n)
			  ) {
				collected->add(n);
			  }
		}
	}
	return collected;
}

//
// nsNodes implementation
//

nsNodes::nsNodes()
: nsNode()
{
}

nsNodes::~nsNodes()
{
	// todo: cleanup
}

void nsNodes::add(nsNode* node)
{
	nodes.push_back(node);
}

void nsNodes::remove(nsNode*)
{
	throw ENotImplemented("remove");
}

void nsNodes::clear()
{
	throw ENotImplemented("clear");
}

unsigned nsNodes::size()
{
	unsigned size =0;
	vector<nsNode*>::iterator it = nodes.begin();
	for(; it!=nodes.end();it++)
	{
		nsNode* n = 0;
		n = *it;
		if(n)
			size+=n->size();
	}
	return size;
}

bool nsNodes::find(nsNode* n)
{
	vector<nsNode*>::iterator i = std::find(nodes.begin(), nodes.end(), n);
	if(i == nodes.end())
		return false;
	else
		return true;
}

void nsNodes::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

nsNode* nsNodes::getByName(const string& name)
{
	vector<nsNode*>::iterator i = nodes.begin();
	for(;i!=nodes.end();i++)
	{
		nsNode* node = *i;
		string fullName = node->getName();
		if(fullName == "")
		{
			throw ENotImplemented("can't find full name");
		}
		else if(fullName == name)
		{
            return node;
 		}
	}
	return 0;
}

nsNode* nsNodes::getByNum(int i)
{
	return (nodes.at(i));
}

nsNode* nsNodes::getByShortName(const string& name)
{
	vector<nsNode*>::iterator i = nodes.begin();
	for(;i!=nodes.end();i++)
	{
		nsNode* node = *i;
		string shortName = node->getShortName();
		if(shortName == "")
		{
			throw ENotImplemented("can't find short name");
		}
		else if(shortName == name)
		{
            return node;
 		}
	}
	return 0;
}

/*nsNodes::~nsNodes()
{
}

nsNodes::nsNodes()
{
	i=0;
}

void nsNodes::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

unsigned nsNodes::size()
{
	unsigned size =0;

	std::vector<nsNode*>::iterator it = nodes.begin();
	for(; it!=nodes.end();it++)
	{
		nsNode* n = 0;
		n = *it;
		if(n)
			size+=n->size();
	}

	return size;
}

void nsNodes::add(nsNode* n)
{
	if(n){
		nodes.push_back(n);
		i++;
	}
	else
	{
		ex_fatal("can't add null node!");
	}	
}

nsNode* nsNodes::getByNum(int i_)
{
	if(i_ < nodes.size()) return nodes[i_];
	return 0;
}*/

// -------------------------------------------------------

nsRetStmt::nsRetStmt()
{
//	setName("return");
}

void nsRetStmt::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

void nsExpr::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

void nsOperand::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

nsFCall::nsFCall()
{
//	setName("function_call");
}

void nsFCall::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

//
// nsVar implementation
//

nsVar::nsVar()
{
	_isLocal = false;
}

void nsVar::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

bool nsVar::isPointer()
{
	return !getType()->isEmbedded();
}

//
// nsArg implementation
//

nsArg::nsArg()
{
//	setName("arg");
}

void nsArg::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

void nsAArg::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

nsNumber::nsNumber()
{
//	setName("number");
}

void nsNumber::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

void nsBlock::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

//
// nsVarDec implementation
//

nsVarDec::nsVarDec()
{
	_isField = false;
}

void nsVarDec::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

//
// nsClass implementation
//

void nsClass::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

void nsClass::addField(nsField* fieldNode)
{
	fields.add(fieldNode);
}

void nsClass::addMethod(nsMethod* methodNode)
{
	methods.add(methodNode);
}

nsField* nsClass::getFieldByShortName(const string& fieldName)
{
	return (nsField*) fields.getByShortName(fieldName);
}

nsMethod* nsClass::getMethodByShortName(const string& methodName)
{
	return (nsMethod*) methods.getByShortName(methodName);
}

nsField* nsClass::getFieldByName(const string& fieldName)
{
	// todo: add code here
	throw ENotImplemented("getFieldByName");
}

nsMethod* nsClass::getMethodByName(const string& methodName)
{
	// todo: add code here
	throw ENotImplemented("getMethodByName");
}

string nsClass::extractClassName(const string& className)
{
	// todo: add code here
	throw ENotImplemented("extractClassName");
}

unsigned int nsClass::size() 
{
	return methods.size() + fields.size();
}

//
// nsField implementation
//

void nsField::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

//
// nsMethod implementation
//

void nsMethod::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

// 
// nsRef implementation
//

nsRef::nsRef()
{
	object=0;
}

void nsRef::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

void nsRef::setRef(nsOperand* object)
{
	if(!object)
		return;
	this->object = object;
	object->parent = this;
}

//
// nsSelfRef implementation
//

nsSelfRef::nsSelfRef()
: nsRef()
{
}

void nsSelfRef::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}

//
// nsMethodCall implementation
//

nsMethodCall::nsMethodCall()
{
}

void nsMethodCall::traverse(nsAsmGenerator* tr)
{
	tr->traverse(this);
}
